home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xmbase-grok-1.2
/
util.c
< prev
Wrap
C/C++ Source or Header
|
1995-06-25
|
13KB
|
540 lines
/*
* Initializes everything and starts a calendar window for the current
* month. The interval timer (for autosave and entry recycling) and a
* few routines used by everyone are also here.
*
* section_name(db,n) return name of section nsect
* resolve_tilde(path) return path with ~ replaced with home
* directory as found in $HOME
* find_file(buf, name,exec) find file <name> and store the path
* in <buf>. Return FALSE if not found.
* fatal(char *fmt, ...) Prints an error message and exits.
* print_button(w, fmt, ...) Prints a string into a string Label
* or PushButton. %s may not be NULL.
* print_text_button(w, fmt, ...) Prints a string into a Text button.
* %s may not be NULL.
* print_text_button_s(w, str) Prints a string, str may be NULL
* set_icon(shell, sub) changes the icon pixmap of a window
* truncate_string(str,len,sfont) truncate string to fit into <len>
* strlen_in_pixels(str, sfont) return length of string in pixels
*
* to_octal(n) convert ascii to octal string
* to_ascii(str, def) convert octal string to ascii
*/
#include "config.h"
#include <X11/Xos.h>
#include <stdarg.h>
#include <stdlib.h>
#include <pwd.h>
#include <signal.h>
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include "grok.h"
#include "form.h"
#include "proto.h"
#include "patchlevel.h"
#include "bm_icon.h"
extern Display *display; /* everybody uses the same server */
extern GC gc; /* everybody uses this context */
extern Widget toplevel; /* top-level shell for icon name */
extern struct config config; /* global configuration data */
extern XFontStruct *font[NFONTS]; /* fonts: FONT_* */
extern Pixel color[NCOLS]; /* colors: COL_* */
extern char *progname; /* argv[0] */
/*
* extract a section name from the section paths by removing the extension
* and common substrings.
*/
char *section_name(
register DBASE *dbase, /* contains section array */
int n) /* 0 .. dbase->nsects-1 */
{
static char name[40]; /* returned name */
register SECTION *sect; /* section list */
register char *path; /* path to reduce */
register char *trunc; /* trailing unique part */
register int i; /* section counter */
if (!dbase || n < 0 || n >= dbase->nsects)
return("");
sect = dbase->sect;
path = sect[n].path;
if (!path || !*path)
return("");
trunc = strrchr(sect[n].path, '/');
while (trunc > path) {
for (i=dbase->nsects-1; i >= 0; i--)
if (i != n && strncmp(path, sect[i].path, trunc-path))
break;
if (i < 0)
break;
while (trunc > path && *trunc != '/')
trunc--;
}
if (!trunc)
trunc = path;
else if (*trunc == '/')
trunc++;
i = strlen(trunc);
if (i > sizeof(name)-1)
sprintf(name, "...%s", trunc + i - (sizeof(name)-4));
else
strcpy(name, trunc);
if ((trunc = strrchr(name, '.')) && trunc > strrchr(name , '/'))
*trunc = 0;
return(name);
}
/*
* If <path> begins with a tilde, replace the tilde with $HOME. This is used
* for the database files, and the holiday file (see holiday.c). If the path
* is relative (ie., does not begin with ~ or !) and does not begin with "./",
* prepend GROKDIR and append ext. This is the default, all files are normally
* in ~/.grok. Also strip unnecessary leading and trailing / and /. to prevent
* forms from appearing multiple times in the database pulldown.
*/
char *resolve_tilde(
char *path, /* path with ~ */
char *ext) /* append extension unless 0 */
{
struct passwd *pw; /* for searching home dirs */
static char pathbuf[1024]; /* path with ~ expanded */
char buf[1024]; /* buf for prepending GROKDIR*/
char *p, *q; /* username copy pointers */
char *home = 0; /* home dir (if ~ in path) */
int i; /* strip trailing / and /. */
if (*path != '~' && *path != '/' && (*path != '.' || path[1] != '/')) {
sprintf(buf, "%s/%s", GROKDIR, path);
path = buf;
if (ext) {
if ((p = strrchr(path, '.')) && !strcmp(p+1, ext))
*p = 0;
strcat(path, ".");
strcat(path, ext);
}
}
if (*path == '~') {
if (!path[1] || path[1] == '/') {
*pathbuf = 0;
if (!(home = getenv("HOME")))
home = getenv("home");
path += 2;
} else {
for (path++,q=pathbuf; *path && *path!='/'; path++,q++)
*q = *path;
path++;
*q = 0;
if (pw = getpwnam(pathbuf))
home = pw->pw_dir;
}
if (!home) {
fprintf(stderr,
"%s: can't evaluate ~%s in %s, using .\n",
progname, pathbuf, path);
home = ".";
}
sprintf(pathbuf, "%s/%s", home, path);
path = pathbuf;
}
for (i=strlen(path)-1; i > 0; )
if (path[i] == '/' || path[i] == '.' && path[i-1] == '/')
path[i--] = 0;
else
break;
return(path);
}
/*
* locate a program or file, and return its complete path. This is used by
* the daemon to locate notifier and user programs, and by grok to locate
* grok.hlp. Assume that <buf> has space for 1024 chars. PATH is a macro
* defined by the Makefile.
*/
#ifndef PATH
#define PATH 0
#endif
#define DEFAULTPATH "/usr/local/bin:/usr/local/lib:/bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/bsd:/usr/bin/X11:."
BOOL find_file(
char *buf, /* buffer for returned path */
char *name, /* file name to locate */
BOOL exec) /* must be executable? */
{
int method; /* search path counter */
char *path; /* $PATH or DEFAULTPATH */
int namelen; /* len of tail of name */
register char *p, *q; /* string copy pointers */
if (*name == '/') { /* begins with / */
strcpy(buf, name);
return(TRUE);
}
if (*name == '~') { /* begins with ~ */
strcpy(buf, resolve_tilde(name, 0));
return(TRUE);
}
namelen = strlen(name);
for (method=0; ; method++) {
switch(method) {
case 0: path = PATH; break;
case 1: path = getenv("GROK_PATH"); break;
case 2: path = getenv("PATH"); break;
case 3: path = DEFAULTPATH; break;
default: return(FALSE);
}
if (!path)
continue;
do {
q = buf;
p = path;
while (*p && *p != ':' && q < buf + 1021 - namelen)
*q++ = *p++;
*q++ = '/';
strcpy(q, name);
if (!access(buf, exec ? X_OK : R_OK))
return(TRUE);
*buf = 0;
path = p+1;
} while (*p);
}
return(FALSE); /* for lint */
}
/*
* whenever something goes seriously wrong, this routine is called. It makes
* code easier to read. fatal() never returns.
*/
/*VARARGS*/
void fatal(char *fmt, ...)
{
va_list parm;
va_start(parm, fmt);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, fmt, parm);
va_end(parm);
putc('\n', stderr);
exit(1);
}
/*
* Ultrix doesn't have strdup, so we'll need to define one locally.
*/
char *mystrdup(
register char *s)
{
register char *p = NULL;
if (s && (p = (char *)malloc(strlen(s)+1)))
strcpy(p, s);
return(p);
}
/*
* some systems use mybzero (BSD), others memset (SysV), I'll roll my own...
*/
void mybzero(
void *p,
register int n)
{
register char *q = p;
while (n--) *q++ = 0;
}
/*
* Sinix doesn't have strcasecmp, so here is my own. Not as efficient as
* the canonical implementation, but short, and it's not time-critical.
*/
int mystrcasecmp(
register char *a,
register char *b)
{
register char ac, bc;
while ((ac = *a++) && (bc = *b++)) {
if (ac <= 'Z' && ac >= 'A') ac += 'a' - 'A';
if (bc <= 'Z' && bc >= 'A') bc += 'a' - 'A';
if (ac != bc)
break;
}
return(ac - bc);
}
/*---------------------------------------------------------------------------*/
/*
* draw some text into a button. This is here because it's used by many
* routines.
*/
void print_button(Widget w, char *fmt, ...)
{
va_list parm;
Arg args;
XmString string;
char buf[1024];
if (w) {
va_start(parm, fmt);
if (!fmt) fmt = "";
vsprintf(buf, fmt, parm);
va_end(parm);
string = XmStringCreateSimple(buf);
XtSetArg(args, XmNlabelString, string);
XtSetValues(w, &args, 1);
XmStringFree(string);
}
}
void print_text_button(Widget w, char *fmt, ...)
{
va_list parm;
XmString string;
char buf[1024];
if (w) {
va_start(parm, fmt);
if (!fmt) fmt = "";
vsprintf(buf, fmt, parm);
va_end(parm);
string = XmStringCreateSimple(buf);
XmTextSetString(w, buf);
XmTextSetInsertionPosition(w, strlen(buf));
XmStringFree(string);
}
}
void print_text_button_s(Widget w, char *str)
{
XmString string;
if (!w)
return;
if (!str)
str = "";
string = XmStringCreateSimple(str);
XmTextSetString(w, str);
XmTextSetInsertionPosition(w, strlen(str));
XmStringFree(string);
}
/*
* turn radio button on or off
*/
void set_toggle(
Widget w,
BOOL set)
{
Arg arg;
if (w) {
XtSetArg(arg, XmNset, set);
XtSetValues(w, &arg, 1);
}
}
/*
* return the text string in a text button. If ptr==0, return a static
* buffer containing the text; else assume that ptr points to a strdup'ed
* pointer. Free it if nonzero, then strdup the new text.
*/
static char *readbutton(
Widget w,
char **ptr,
BOOL skipblank,
BOOL noblanks)
{
char *string, *s; /* contents of text widget */
static char *buf;
static int bufsize;
int size;
if (w) {
s = string = XmTextGetString(w);
if (skipblank) {
while (*s == ' ' || *s == '\t')
s++;
if (noblanks)
for (size=0; s[size]; size++)
if (s[size] == ' ' || s[size] == '\t')
s[size] = '_';
size = strlen(s);
while (size && (s[size-1] == ' ' || s[size-1] == '\t'))
size--;
s[size++] = 0;
} else
size = strlen(s) + 1;
if (size > bufsize) {
if (buf) free(buf);
if (!(buf = malloc(bufsize = size)))
return(0);
}
strcpy(buf, s);
XtFree(string);
} else if (buf)
*buf = 0;
if (ptr) {
if (*ptr) free(*ptr);
*ptr = buf && *buf ? mystrdup(buf) : 0;
}
return(buf);
}
char *read_text_button_noskipblank(Widget w, char **ptr)
{ return(readbutton(w, ptr, FALSE, FALSE)); }
char *read_text_button(Widget w, char **ptr)
{ return(readbutton(w, ptr, TRUE, FALSE)); }
char *read_text_button_noblanks(Widget w, char **ptr)
{ return(readbutton(w, ptr, TRUE, TRUE)); }
/*
* set icon for the application or a shell.
*/
void set_icon(
Widget shell,
int sub) /* 0=main, 1=submenu */
{
#ifndef sgi
Pixmap icon;
if (icon = XCreatePixmapFromBitmapData(display,
DefaultRootWindow(display),
(char *)(sub ? bm_icon_bits : bm_icon_bits),
bm_icon_width, bm_icon_height,
BlackPixelOfScreen(XtScreen(shell)),
WhitePixelOfScreen(XtScreen(shell)),
DefaultDepth(display, DefaultScreen(display))))
XtVaSetValues(shell, XmNiconPixmap, icon, NULL);
#endif
}
/*
* set mouse cursor to one of the predefined shapes. This is used in the
* form editor's canvas drawing area. The list of supported cursors is in
* <X11/cursorfont.h>.
*/
void set_cursor(
Widget w, /* in which widget */
int n) /* which cursor, one of XC_* */
{
static Cursor cursor[XC_num_glyphs];
if (!cursor[n])
cursor[n] = XCreateFontCursor(display, n);
XDefineCursor(display, XtWindow(w), cursor[n]);
}
/*
* truncate <string> such that it is not longer than <len> pixels when
* drawn with font <sfont>, by storing \0 somewhere in the string.
*/
void truncate_string(
register char *string, /* string to truncate */
register int len, /* max len in pixels */
int sfont) /* font of string */
{
while (*string) {
len -= font[sfont]->per_char
[*string - font[sfont]->min_char_or_byte2].width;
if (len < 0)
*string = 0;
else
string++;
}
}
/*
* return the length of <string> in pixels, when drawn with <sfont>
*/
int strlen_in_pixels(
register char *string, /* string to truncate */
int sfont) /* font of string */
{
register int len = 0; /* max len in pixels */
while (*string) {
len += font[sfont]->per_char
[*string - font[sfont]->min_char_or_byte2].width;
string++;
}
return(len);
}
/*
* convert ascii code to and from a string representation. This is used for
* a few input buttons in the form editor window that accept single chars.
*/
char *to_octal(
int n) /* ascii to convert to string */
{
static char buf[8];
if (n == '\t') return("\\t");
if (n == '\n') return("\\n");
if (n <= 0x20 || n >= 0x7f) { sprintf(buf, "\\%03o", n); }
else { buf[0] = n; buf[1] = 0; }
return(buf);
}
char to_ascii(
char *str, /* string to convert to ascii */
int def) /* default if string is empty */
{
int n;
char *p = str;
if (!p)
return(def);
while (*p == ' ' || *p == '\t') p++;
if (!*p)
return(def);
if (*p == '\\') {
if (p[1] == 't') return('\t');
if (p[1] == 'n') return('\n');
if (p[1] >= '0' &&
p[1] <= '7') { sscanf(p+1, "%o", &n); return(n); }
if (p[1] == 'x') { sscanf(p+2, "%x", &n); return(n); }
return('\\');
} else
return(*p);
}